package com.ruoyi.system.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.system.domain.BizPurchaseInBarcode;
import com.ruoyi.system.mapper.BizPurchaseInMapper;
import com.ruoyi.system.mapper.BizBarcodeMapper;
import com.ruoyi.system.mapper.BizReceiptNoteMapper;
import com.ruoyi.system.domain.BizPurchaseIn;
import com.ruoyi.system.service.IBizPurchaseInService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.BizReceiptNote;
import com.ruoyi.system.domain.BizBarcode;
import com.ruoyi.common.exception.ServiceException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 * 采购入库单Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-11-01
 */
@Service
public class BizPurchaseInServiceImpl implements IBizPurchaseInService 
{
    @Autowired
    private BizPurchaseInMapper bizPurchaseInMapper;

    @Autowired
    private BizBarcodeMapper bizBarcodeMapper;

    @Autowired
    private BizReceiptNoteMapper bizReceiptNoteMapper;

    @Autowired
    private com.ruoyi.system.mapper.BizPurchaseOrderMapper bizPurchaseOrderMapper;

    /**
     * 查询采购入库单
     * 
     * @param purchaseInId 采购入库单主键
     * @return 采购入库单
     */
    @Override
    public BizPurchaseIn selectBizPurchaseInByPurchaseInId(Long purchaseInId)
    {
        return bizPurchaseInMapper.selectBizPurchaseInByPurchaseInId(purchaseInId);
    }

    /**
     * 查询采购入库单列表
     * 
     * @param bizPurchaseIn 采购入库单
     * @return 采购入库单
     */
    @Override
    public List<BizPurchaseIn> selectBizPurchaseInList(BizPurchaseIn bizPurchaseIn)
    {
        return bizPurchaseInMapper.selectBizPurchaseInList(bizPurchaseIn);
    }

    /**
     * 新增采购入库单
     * 
     * @param bizPurchaseIn 采购入库单
     * @return 结果
     */
    @Transactional
    @Override
    public int insertBizPurchaseIn(BizPurchaseIn bizPurchaseIn)
    {
        // 自动生成采购入库单号：PI + yyyyMMdd + 三位流水
        if (StringUtils.isEmpty(bizPurchaseIn.getPurchaseInNo())) {
            bizPurchaseIn.setPurchaseInNo(generatePurchaseInNo());
        }
        // 设置审计字段（避免 created_by/created_time 为空导致插入失败）
        if (StringUtils.isEmpty(bizPurchaseIn.getCreatedBy())) {
            bizPurchaseIn.setCreatedBy(SecurityUtils.getUsername());
        }
        if (bizPurchaseIn.getCreatedTime() == null) {
            bizPurchaseIn.setCreatedTime(DateUtils.getNowDate());
        }
        // 计算总箱数与总数量（基于箱码明细）
        Long totalBoxes = 0L;
        java.math.BigDecimal totalQuantity = java.math.BigDecimal.ZERO;
        List<BizPurchaseInBarcode> srcList = bizPurchaseIn.getBizPurchaseInBarcodeList();
        if (StringUtils.isNotNull(srcList)) {
            for (BizPurchaseInBarcode rb : srcList) {
                totalBoxes += 1;
                if (rb.getPackQuantity() != null) {
                    totalQuantity = totalQuantity.add(rb.getPackQuantity());
                }
            }
        }
        bizPurchaseIn.setTotalBoxes(totalBoxes);
        bizPurchaseIn.setTotalQuantity(totalQuantity);
        // 解析并补充收料通知单ID，避免数据库非空约束错误
        if (bizPurchaseIn.getReceiptNoteId() == null) {
            String receiptNoteNo = bizPurchaseIn.getReceiptNoteNo();
            // 若未显式带入收料通知单号，则从箱码明细尝试解析
            if (StringUtils.isEmpty(receiptNoteNo)) {
                List<BizPurchaseInBarcode> srcListForResolve = bizPurchaseIn.getBizPurchaseInBarcodeList();
                if (StringUtils.isNotNull(srcListForResolve)) {
                    for (BizPurchaseInBarcode src : srcListForResolve) {
                        if (src.getBarcodeId() != null) {
                            BizBarcode bc = bizBarcodeMapper.selectBizBarcodeByBarcodeId(src.getBarcodeId());
                            if (bc != null && StringUtils.isNotEmpty(bc.getReceiptNoteNo())) {
                                receiptNoteNo = bc.getReceiptNoteNo();
                                break;
                            }
                        } else if (StringUtils.isNotEmpty(src.getBarcode())) {
                            BizBarcode query = new BizBarcode();
                            query.setBarcode(src.getBarcode());
                            List<BizBarcode> found = bizBarcodeMapper.selectBizBarcodeList(query);
                            if (found != null && !found.isEmpty() && StringUtils.isNotEmpty(found.get(0).getReceiptNoteNo())) {
                                receiptNoteNo = found.get(0).getReceiptNoteNo();
                                break;
                            }
                        }
                    }
                }
            }
            if (StringUtils.isNotEmpty(receiptNoteNo)) {
                BizReceiptNote rnQuery = new BizReceiptNote();
                rnQuery.setReceiptNoteNo(receiptNoteNo);
                List<BizReceiptNote> rnList = bizReceiptNoteMapper.selectBizReceiptNoteList(rnQuery);
                if (rnList != null && !rnList.isEmpty()) {
                    bizPurchaseIn.setReceiptNoteNo(receiptNoteNo);
                    bizPurchaseIn.setReceiptNoteId(rnList.get(0).getReceiptNoteId());
                } else {
                    throw new ServiceException("未找到收料通知单：" + receiptNoteNo);
                }
            } else {
                throw new ServiceException("未能解析收料通知单，请选择或扫描关联箱码");
            }
        }
        // 解析并补充送货单号，避免数据库非空约束错误
        if (StringUtils.isEmpty(bizPurchaseIn.getDeliveryNoteNo())) {
            String deliveryNoteNo = null;
            // 优先从已解析的收料通知单获取（如果存在）
            if (bizPurchaseIn.getReceiptNoteId() != null) {
                BizReceiptNote rn = bizReceiptNoteMapper.selectBizReceiptNoteByReceiptNoteId(bizPurchaseIn.getReceiptNoteId());
                if (rn != null) {
                    if (StringUtils.isNotEmpty(rn.getDeliveryNoteNo())) {
                        deliveryNoteNo = rn.getDeliveryNoteNo();
                    }
                    // 同步供应商信息（如未显式传入）
                    if (StringUtils.isEmpty(bizPurchaseIn.getSupplierCode()) && StringUtils.isNotEmpty(rn.getSupplierCode())) {
                        bizPurchaseIn.setSupplierCode(rn.getSupplierCode());
                    }
                    if (StringUtils.isEmpty(bizPurchaseIn.getSupplierName()) && StringUtils.isNotEmpty(rn.getSupplierName())) {
                        bizPurchaseIn.setSupplierName(rn.getSupplierName());
                    }
                }
            } else if (StringUtils.isNotEmpty(bizPurchaseIn.getReceiptNoteNo())) {
                BizReceiptNote rnQuery2 = new BizReceiptNote();
                rnQuery2.setReceiptNoteNo(bizPurchaseIn.getReceiptNoteNo());
                List<BizReceiptNote> rnList2 = bizReceiptNoteMapper.selectBizReceiptNoteList(rnQuery2);
                if (rnList2 != null && !rnList2.isEmpty() && StringUtils.isNotEmpty(rnList2.get(0).getDeliveryNoteNo())) {
                    deliveryNoteNo = rnList2.get(0).getDeliveryNoteNo();
                    // 同步供应商信息（如未显式传入）
                    if (StringUtils.isEmpty(bizPurchaseIn.getSupplierCode()) && StringUtils.isNotEmpty(rnList2.get(0).getSupplierCode())) {
                        bizPurchaseIn.setSupplierCode(rnList2.get(0).getSupplierCode());
                    }
                    if (StringUtils.isEmpty(bizPurchaseIn.getSupplierName()) && StringUtils.isNotEmpty(rnList2.get(0).getSupplierName())) {
                        bizPurchaseIn.setSupplierName(rnList2.get(0).getSupplierName());
                    }
                }
            }
            // 若仍未解析到，则尝试从箱码明细解析
            if (StringUtils.isEmpty(deliveryNoteNo)) {
                List<BizPurchaseInBarcode> srcListForResolve2 = bizPurchaseIn.getBizPurchaseInBarcodeList();
                if (StringUtils.isNotNull(srcListForResolve2)) {
                    for (BizPurchaseInBarcode src : srcListForResolve2) {
                        if (src.getBarcodeId() != null) {
                            BizBarcode bc = bizBarcodeMapper.selectBizBarcodeByBarcodeId(src.getBarcodeId());
                            if (bc != null && StringUtils.isNotEmpty(bc.getDeliveryNoteNo())) {
                                deliveryNoteNo = bc.getDeliveryNoteNo();
                                break;
                            }
                        } else if (StringUtils.isNotEmpty(src.getBarcode())) {
                            BizBarcode query2 = new BizBarcode();
                            query2.setBarcode(src.getBarcode());
                            List<BizBarcode> found2 = bizBarcodeMapper.selectBizBarcodeList(query2);
                            if (found2 != null && !found2.isEmpty() && StringUtils.isNotEmpty(found2.get(0).getDeliveryNoteNo())) {
                                deliveryNoteNo = found2.get(0).getDeliveryNoteNo();
                                break;
                            }
                        }
                    }
                }
            }
            if (StringUtils.isNotEmpty(deliveryNoteNo)) {
                bizPurchaseIn.setDeliveryNoteNo(deliveryNoteNo);
            } else {
                throw new ServiceException("未能解析送货单号，请选择或扫描关联箱码");
            }
        }
        // 入库主表默认设置为已确认（CONFIRMED），并填充入库日期/确认人/确认时间/入库人
        if (StringUtils.isEmpty(bizPurchaseIn.getPutawayStatus())) {
            bizPurchaseIn.setPutawayStatus("CONFIRMED");
        }
        if (bizPurchaseIn.getPutawayDate() == null) {
            bizPurchaseIn.setPutawayDate(DateUtils.getNowDate());
        }
        if (StringUtils.isEmpty(bizPurchaseIn.getPutawayOperator())) {
            bizPurchaseIn.setPutawayOperator(SecurityUtils.getUsername());
        }
        if (StringUtils.isEmpty(bizPurchaseIn.getConfirmedBy())) {
            bizPurchaseIn.setConfirmedBy(SecurityUtils.getUsername());
        }
        if (bizPurchaseIn.getConfirmedTime() == null) {
            bizPurchaseIn.setConfirmedTime(DateUtils.getNowDate());
        }
        int rows = bizPurchaseInMapper.insertBizPurchaseIn(bizPurchaseIn);
        insertBizPurchaseInBarcode(bizPurchaseIn);
        // 批量更新主条码为入库完成，并写入入库单号与入库时间
        List<Long> barcodeIds = new ArrayList<>();
        List<BizPurchaseInBarcode> srcListForUpdate = bizPurchaseIn.getBizPurchaseInBarcodeList();
        if (StringUtils.isNotNull(srcListForUpdate)) {
            for (BizPurchaseInBarcode rb : srcListForUpdate) {
                if (rb.getBarcodeId() != null) {
                    barcodeIds.add(rb.getBarcodeId());
                }
            }
        }
        if (!barcodeIds.isEmpty()) {
            bizBarcodeMapper.batchUpdatePutawayStatus(
                bizPurchaseIn.getPurchaseInNo(),
                DateUtils.getNowDate(),
                barcodeIds.toArray(new Long[0])
            );
        }
        // 根据本次扫码的箱码，更新对应采购订单明细的已入库数量与状态
        updateOrderItemPutawayAndStatus(bizPurchaseIn);
        return rows;
    }

    /**
     * 修改采购入库单
     * 
     * @param bizPurchaseIn 采购入库单
     * @return 结果
     */
    @Transactional
    @Override
    public int updateBizPurchaseIn(BizPurchaseIn bizPurchaseIn)
    {
        // 入库主表默认设置为已确认（CONFIRMED），并填充入库日期/确认人/确认时间/入库人
        if (StringUtils.isEmpty(bizPurchaseIn.getPutawayStatus())) {
            bizPurchaseIn.setPutawayStatus("CONFIRMED");
        }
        if (bizPurchaseIn.getPutawayDate() == null) {
            bizPurchaseIn.setPutawayDate(DateUtils.getNowDate());
        }
        if (StringUtils.isEmpty(bizPurchaseIn.getPutawayOperator())) {
            bizPurchaseIn.setPutawayOperator(SecurityUtils.getUsername());
        }
        if (StringUtils.isEmpty(bizPurchaseIn.getConfirmedBy())) {
            bizPurchaseIn.setConfirmedBy(SecurityUtils.getUsername());
        }
        if (bizPurchaseIn.getConfirmedTime() == null) {
            bizPurchaseIn.setConfirmedTime(DateUtils.getNowDate());
        }
        // 更新审计字段
        bizPurchaseIn.setUpdatedBy(SecurityUtils.getUsername());
        bizPurchaseIn.setUpdatedTime(DateUtils.getNowDate());

        bizPurchaseInMapper.deleteBizPurchaseInBarcodeByPurchaseInId(bizPurchaseIn.getPurchaseInId());
        insertBizPurchaseInBarcode(bizPurchaseIn);
        // 在修改入库单时，同步更新主条码为入库完成状态
        List<Long> barcodeIds = new ArrayList<>();
        List<BizPurchaseInBarcode> srcListForUpdate = bizPurchaseIn.getBizPurchaseInBarcodeList();
        if (StringUtils.isNotNull(srcListForUpdate)) {
            for (BizPurchaseInBarcode rb : srcListForUpdate) {
                if (rb.getBarcodeId() != null) {
                    barcodeIds.add(rb.getBarcodeId());
                }
            }
        }
        if (!barcodeIds.isEmpty()) {
            bizBarcodeMapper.batchUpdatePutawayStatus(
                bizPurchaseIn.getPurchaseInNo(),
                DateUtils.getNowDate(),
                barcodeIds.toArray(new Long[0])
            );
        }
        // 根据本次扫码的箱码，更新对应采购订单明细的已入库数量与状态
        updateOrderItemPutawayAndStatus(bizPurchaseIn);
        return bizPurchaseInMapper.updateBizPurchaseIn(bizPurchaseIn);
    }

    /**
     * 批量删除采购入库单
     * 
     * @param purchaseInIds 需要删除的采购入库单主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteBizPurchaseInByPurchaseInIds(Long[] purchaseInIds)
    {
        bizPurchaseInMapper.deleteBizPurchaseInBarcodeByPurchaseInIds(purchaseInIds);
        return bizPurchaseInMapper.deleteBizPurchaseInByPurchaseInIds(purchaseInIds);
    }

    /**
     * 删除采购入库单信息
     * 
     * @param purchaseInId 采购入库单主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteBizPurchaseInByPurchaseInId(Long purchaseInId)
    {
        bizPurchaseInMapper.deleteBizPurchaseInBarcodeByPurchaseInId(purchaseInId);
        return bizPurchaseInMapper.deleteBizPurchaseInByPurchaseInId(purchaseInId);
    }

    /**
     * 新增采购入库箱码明细信息
     * 
     * @param bizPurchaseIn 采购入库单对象
     */
    public void insertBizPurchaseInBarcode(BizPurchaseIn bizPurchaseIn)
    {
        List<BizPurchaseInBarcode> bizPurchaseInBarcodeList = bizPurchaseIn.getBizPurchaseInBarcodeList();
        Long purchaseInId = bizPurchaseIn.getPurchaseInId();
        if (StringUtils.isNotNull(bizPurchaseInBarcodeList))
        {
            List<BizPurchaseInBarcode> list = new ArrayList<BizPurchaseInBarcode>();
            for (BizPurchaseInBarcode bizPurchaseInBarcode : bizPurchaseInBarcodeList)
            {
                bizPurchaseInBarcode.setPurchaseInId(purchaseInId);
                // 明细审计字段默认值
                if (StringUtils.isEmpty(bizPurchaseInBarcode.getCreatedBy())) {
                    bizPurchaseInBarcode.setCreatedBy(SecurityUtils.getUsername());
                }
                if (bizPurchaseInBarcode.getCreatedTime() == null) {
                    bizPurchaseInBarcode.setCreatedTime(DateUtils.getNowDate());
                }
                // 绑定主表的仓库信息与入库操作人
                if (StringUtils.isEmpty(bizPurchaseInBarcode.getWarehouseCode())) {
                    bizPurchaseInBarcode.setWarehouseCode(bizPurchaseIn.getWarehouseCode());
                }
                if (StringUtils.isEmpty(bizPurchaseInBarcode.getWarehouseName())) {
                    bizPurchaseInBarcode.setWarehouseName(bizPurchaseIn.getWarehouseName());
                }
                if (StringUtils.isEmpty(bizPurchaseInBarcode.getPutawayOperator())) {
                    bizPurchaseInBarcode.setPutawayOperator(
                        StringUtils.isNotEmpty(bizPurchaseIn.getPutawayOperator()) ? bizPurchaseIn.getPutawayOperator() : SecurityUtils.getUsername()
                    );
                }
                // 默认入库状态与入库时间
                if (StringUtils.isEmpty(bizPurchaseInBarcode.getBarcodeStatus())) {
                    bizPurchaseInBarcode.setBarcodeStatus("PUTAWAY");
                }
                if (bizPurchaseInBarcode.getPutawayTime() == null) {
                    bizPurchaseInBarcode.setPutawayTime(DateUtils.getNowDate());
                }
                list.add(bizPurchaseInBarcode);
            }
            if (list.size() > 0)
            {
                bizPurchaseInMapper.batchBizPurchaseInBarcode(list);
            }
        }
    }

    /**
     * 根据采购入库单中的箱码明细，按采购订单明细项累加已入库数量，并设置明细状态为 PART_PUTAWAY / FULL_PUTAWAY
     */
    private void updateOrderItemPutawayAndStatus(BizPurchaseIn bizPurchaseIn) {
        List<BizPurchaseInBarcode> srcList = bizPurchaseIn.getBizPurchaseInBarcodeList();
        if (StringUtils.isNull(srcList) || srcList.isEmpty()) {
            return;
        }
        java.util.Map<Long, java.math.BigDecimal> itemDeltaMap = new java.util.HashMap<>();
        java.util.Set<Long> affectedOrderIds = new java.util.HashSet<>();
        for (BizPurchaseInBarcode rb : srcList) {
            // 通过 barcodeId 或 barcode 查询主条码，拿到 itemId
            Long itemId = null;
            if (rb.getBarcodeId() != null) {
                BizBarcode bc = bizBarcodeMapper.selectBizBarcodeByBarcodeId(rb.getBarcodeId());
                if (bc != null) {
                    itemId = bc.getItemId();
                }
            } else if (StringUtils.isNotEmpty(rb.getBarcode())) {
                BizBarcode query = new BizBarcode();
                query.setBarcode(rb.getBarcode());
                List<BizBarcode> found = bizBarcodeMapper.selectBizBarcodeList(query);
                if (found != null && !found.isEmpty()) {
                    itemId = found.get(0).getItemId();
                }
            }
            if (itemId == null) {
                continue; // 跳过无法定位到明细的箱码
            }
            java.math.BigDecimal qty = rb.getPackQuantity() != null ? rb.getPackQuantity() : java.math.BigDecimal.ZERO;
            itemDeltaMap.merge(itemId, qty, java.math.BigDecimal::add);
        }
        if (itemDeltaMap.isEmpty()) {
            return;
        }
        String updatedBy = SecurityUtils.getUsername();
        java.util.Date updatedTime = DateUtils.getNowDate();
        for (java.util.Map.Entry<Long, java.math.BigDecimal> e : itemDeltaMap.entrySet()) {
            Long itemId = e.getKey();
            java.math.BigDecimal delta = e.getValue();
            if (delta == null || java.math.BigDecimal.ZERO.compareTo(delta) == 0) {
                continue;
            }
            // 读取明细，计算新的已入库数量
            com.ruoyi.system.domain.BizPurchaseOrderItem item = bizPurchaseOrderMapper.selectBizPurchaseOrderItemByItemId(itemId);
            if (item == null) {
                continue;
            }
            if (item.getOrderId() != null) {
                affectedOrderIds.add(item.getOrderId());
            }
            java.math.BigDecimal current = item.getPutawayQuantity() != null ? item.getPutawayQuantity() : java.math.BigDecimal.ZERO;
            java.math.BigDecimal newPutaway = current.add(delta);
            // 写入新的已入库数量
            bizPurchaseOrderMapper.updateBizPurchaseOrderItemPutawayQuantity(itemId, newPutaway, updatedBy, updatedTime);
            // 根据订单数量判断状态：满则 FULL_PUTAWAY，否则 PART_PUTAWAY（>0）
            java.math.BigDecimal orderQty = item.getOrderQuantity() != null ? item.getOrderQuantity() : java.math.BigDecimal.ZERO;
            String itemStatus;
            if (orderQty.compareTo(java.math.BigDecimal.ZERO) > 0 && newPutaway.compareTo(orderQty) >= 0) {
                itemStatus = "FULL_PUTAWAY";
            } else if (newPutaway.compareTo(java.math.BigDecimal.ZERO) > 0) {
                itemStatus = "PART_PUTAWAY";
            } else {
                itemStatus = item.getItemStatus(); // 保留原状态
            }
            if (StringUtils.isNotEmpty(itemStatus)) {
                bizPurchaseOrderMapper.updateBizPurchaseOrderItemStatus(itemId, itemStatus, updatedBy, updatedTime);
            }
        }

        // 更新主表总已入库与状态（当总数量与总已入库相等时置为 COMPLETED）
        if (!affectedOrderIds.isEmpty()) {
            for (Long oid : affectedOrderIds) {
                bizPurchaseOrderMapper.updateBizPurchaseOrderHeaderPutawayAndStatus(oid, updatedBy, updatedTime);
            }
        }
    }

    /**
     * 生成采购入库单号：PI + yyyyMMdd + 三位流水（001 开始）
     */
    private String generatePurchaseInNo() {
        String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "PI" + dateStr;
        String maxNo = bizPurchaseInMapper.selectMaxPurchaseInNoByDate(prefix);
        int next = 1;
        if (StringUtils.isNotEmpty(maxNo)) {
            String suffix = maxNo.substring(prefix.length());
            try {
                next = Integer.parseInt(suffix) + 1;
            } catch (Exception e) {
                next = 1;
            }
        }
        return prefix + String.format("%03d", next);
    }
}
